/**
  ******************************************************************************
  * @file    main.c
  * @author  MCD Application Team
  * @version V4.0.0
  * @date    21-January-2013
  * @brief   Mass Storage demo main file
  ******************************************************************************
  * @attention
  *
  * <h2><center>&copy; COPYRIGHT 2013 STMicroelectronics</center></h2>
  *
  * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
  * You may not use this file except in compliance with the License.
  * You may obtain a copy of the License at:
  *
  *        http://www.st.com/software_license_agreement_liberty_v2
  *
  * Unless required by applicable law or agreed to in writing, software 
  * distributed under the License is distributed on an "AS IS" BASIS, 
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  *
  ******************************************************************************
  */


/* Includes ------------------------------------------------------------------*/
#include "hw_config.h" 
#include "stm32f10x_flash.h"

#include <stdio.h>
//
#include "integer.h"//for File-system
#include "ff.h"//for File-system
#include "diskio.h"//for File-system

//0x01:add SD card,I2C,FPGA SPI,MCO 8MHz.
//0x02:
#define MCU_FW (0x01)

extern uint16_t MAL_Init (uint8_t lun);

/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Extern variables ----------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*/


int fputc(int ch, FILE *stream)
{
	
	ITM_SendChar(ch);	
	
  /* Place your implementation of fputc here */
  /* e.g. write a character to the USART */
  USART_SendData(USART1, (uint8_t) ch);

  /* Loop until the end of transmission */
  while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET)
  {}

  return ch;
}

void delay_loop(void)
{
	int i;	
		for (i=0;i<60000;i++)
		{
			//just wait time.
		}	
}
/*******************************************************************************
* Function Name  : main.
* Description    : Main routine.
* Input          : None.
* Output         : None.
* Return         : None.
*******************************************************************************/
void SetupUart1(void)
{
	USART_InitTypeDef USART_InitStructure;
		
	//GPIO_PinRemapConfig(GPIO_Remap_USART1, ENABLE);
	
  USART_InitStructure.USART_BaudRate = 115200;
  USART_InitStructure.USART_WordLength = USART_WordLength_8b;
  USART_InitStructure.USART_StopBits = USART_StopBits_1;
  USART_InitStructure.USART_Parity = USART_Parity_No;
  USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
  USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
	//USART_InitStructure.USART_Mode = USART_Mode_Tx;

  STM_EVAL_COMInit(COM1, &USART_InitStructure);	
}
void MCO_PA8_2_FPGA_CLK(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
  /* Output HSE clock on MCO pin ---------------------------------------------*/
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);

  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_Init(GPIOA, &GPIO_InitStructure);
  RCC_MCOConfig(RCC_MCO_HSE);	
}
void SetVbusInput(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;
  GPIO_Init(GPIOA, &GPIO_InitStructure);	
}
FATFS  g_sFatFs;            // Work area (file system object) for logical drive
FIL 	f1;
const unsigned short bmphdr[27]={
	0x4d42,//0
	0x0036,//1
	0x00c0,//2
	0x0000,//3
	0x0000,//4
	0x0036,//5
	0x0000,//6
	0x0028,//7
	0x0000,//8
	0x0800,//9
	0x0000,//10
	0x0800,//11
	0x0000,//12
	0x0001,//13
	0x0018,//14
	0x0000,//15
	0x0000,//16
	0x0000,//17
	0x0000,//18
	0x0000,//19
	0x0000,//20
	0x0000,//21
	0x0000,//22
	0x0000,//23
	0x0000,//24
	0x0000,//25
	0x0000
};
unsigned char u8rrggbbBuf[512*3];
unsigned short u16SpiRxBuf[256];//512B
void ReadBinFile(void)
{
	UINT	uiWriteLen;
	//unsigned char rrggbb[3];
	//int line;
	int i,j;
//
	if(f_mount(&g_sFatFs,"0:",1) != FR_OK)
	{
			printf("Can't mount SD card\r\n");
			return;
	}
//################################		
	//
	if(f_open(&f1, "0:lion2048.bmp", FA_OPEN_EXISTING|FA_READ)!=FR_OK)
	{	
			printf("Can't Open file\r\n");
			//return;
	}	
	else
	{
		//
		printf("Open Read ok\r\n");
		f_read(&f1,&u16SpiRxBuf[0],42, &uiWriteLen);
		//printf("\r\n");
		//for(j=0;j<(42/2);j++)
		//{	
		//	printf("%4x,",u16SpiRxBuf[j]);
		//}			
		printf("\r\nDone\r\n");
		
	}
	f_close(&f1);	
//	
//################################	
	if(f_open(&f1, "log.bmp", FA_CREATE_ALWAYS | FA_WRITE)!=FR_OK)
	{	
			printf("Can't Open file\r\n");
			return;
	}	
	else
	{	
			f_write(&f1,&bmphdr[0],0x42, &uiWriteLen);
			
			memset ((char *)&u16SpiRxBuf,0,sizeof(u16SpiRxBuf)); /* sets everything to 0 */
			memset ((char *)&u8rrggbbBuf,0,sizeof(u8rrggbbBuf));
			
			//for (line = 0; line<2048; line++)
			//for (line = 0; line<200; line++)//test.
			//{
				for(i=0;i<((2048*2048)/512);i++)
				{
					for(j=0;j<256;j++)
					{
						//16bit color to 24bit.
						u8rrggbbBuf[j*3+0]=(i)&0xff;//B
						u8rrggbbBuf[j*3+1]=0;//G
						u8rrggbbBuf[j*3+2]=0;//R
					}
					for(j=256;j<512;j++)
					{
						//16bit color to 24bit.
						u8rrggbbBuf[j*3+0]=0;//B
						u8rrggbbBuf[j*3+1]=0;//G
						u8rrggbbBuf[j*3+2]=(i)&0xff;//R
					}					
					//	
					if((i%1000)==0) printf(".");//512*1000;//512KB
					f_write(&f1,&u8rrggbbBuf[0],512, &uiWriteLen);
					f_write(&f1,&u8rrggbbBuf[0+512],512, &uiWriteLen);
					f_write(&f1,&u8rrggbbBuf[0+1024],512, &uiWriteLen);
				}
	}	
	f_close(&f1);
//################################	

  f_mount(&g_sFatFs,"0:",NULL);	
	printf("Write file done\r\n");
}
void RTC_Configuration(void)
{
  /* Enable PWR and BKP clocks */
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);

  /* Allow access to BKP Domain */
  PWR_BackupAccessCmd(ENABLE);

  /* Reset Backup Domain */
  BKP_DeInit();

  /* Enable LSE */
	RCC_LSICmd(ENABLE);
  //RCC_LSEConfig(RCC_LSE_ON);
  /* Wait till LSE is ready */
  //while (RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET)
	while (RCC_GetFlagStatus(RCC_FLAG_LSIRDY) == RESET)
  {}

  /* Select LSE as RTC Clock Source */
  //RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);
	RCC_RTCCLKConfig(RCC_RTCCLKSource_LSI);

  /* Enable RTC Clock */
  RCC_RTCCLKCmd(ENABLE);

  /* Wait for RTC registers synchronization */
  RTC_WaitForSynchro();

  /* Wait until last write operation on RTC registers has finished */
  RTC_WaitForLastTask();

  /* Enable the RTC Second */
  //RTC_ITConfig(RTC_IT_SEC, ENABLE);

  /* Wait until last write operation on RTC registers has finished */
  RTC_WaitForLastTask();

  /* Set RTC prescaler: set RTC period to 1sec */
  RTC_SetPrescaler(32767); /* RTC period = RTCCLK/RTC_PR = (32.768 KHz)/(32767+1) */

  /* Wait until last write operation on RTC registers has finished */
  RTC_WaitForLastTask();
}

uint8_t FlashBuf[4096];
typedef  void (*pFunction)(void);
pFunction Jump_To_Application;
uint32_t JumpAddress;
#define ApplicationAddress 0x08003000
#define PAGE_SIZE															((uint16_t)0x100)//256byte
#define APPLICATIONADDRESS                 ((uint32_t)0x08008000) /* User start code space */
    
void iap_delay(	__IO uint32_t nCount)
{
  __IO uint32_t index = 0; 
	
  for(index = (34000 * nCount); index != 0; index--)
  {
  }
}
FIL 	f1;
void GotoIAP(void)
{
	UINT 	uiReadLen;
	uint32_t  i,j;
	uint32_t index ;	
	uint32_t u32FlashPageAddr;	
__IO FLASH_Status FLASHStatus = FLASH_COMPLETE;
	

	
	unsigned short u16progress;	
	uint32_t  fw_size;
	
	index=0;
	
	disk_initialize(0);
	if(f_mount(&g_sFatFs,"0:",1) != FR_OK)	
	{
			printf("\r\rnf_mount fail!!!\r\n");		
			return;
	}

//Get File size!!!
	if(f_open(&f1, "fw.bin", FA_OPEN_EXISTING | FA_READ)!=FR_OK)
	{
		fw_size=0;
		return;
	}	
	else
	{	
		//programm at least one page.
		if((f1.fsize%PAGE_SIZE))	fw_size=f1.fsize+PAGE_SIZE;	
		else											fw_size=f1.fsize;			
	}
	f_close(&f1);
//	
	
	FLASH_Unlock();
	
  /* Clear all pending flags */      
  FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPRTERR);	
	
	// Erase check
	u32FlashPageAddr=APPLICATIONADDRESS;
	for(i=0;i<(fw_size/PAGE_SIZE);i++)
	//for(i=0;i<(((128-8)*1024)/PAGE_SIZE);i++)//erase only 128KB
	//for(i=0;i<(((256-8)*1024)/PAGE_SIZE);i++)//erase only 256KB
	//for(i=0;i<(((384-8)*1024)/PAGE_SIZE);i++)//erase only 384KB
	{
		FLASH_Unlock();
		if(FLASH_ErasePage(u32FlashPageAddr)!=FLASH_COMPLETE)
		{
			/* Clear all pending flags */      
			FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPRTERR);	
			
			while(1)
			{
				//error;
			}
		}	

		u32FlashPageAddr+=PAGE_SIZE;
		
		u16progress=((i*100)/(fw_size/PAGE_SIZE));
		printf("Erase %3d \r\n",u16progress);
	}		

	
	//*************************************************************
#if(0)	
	if(f_open(&f1, "erase.bin", FA_CREATE_ALWAYS | FA_WRITE)!=FR_OK)
	{
		return;
	}		
	u32FlashPageAddr=APPLICATIONADDRESS;
	for(i=0;i<(fw_size/PAGE_SIZE);i++)
	{
		if(f_write(&f1, (const void *)u32FlashPageAddr, PAGE_SIZE, &uiReadLen)!=FR_OK)
		{
			printf("Write file Error\r\n");
		}			
		if(uiReadLen!=PAGE_SIZE) break;
		u32FlashPageAddr+=PAGE_SIZE;	
		
		LCD_Gotoxy(0,0);
		u16progress=((i*100)/(fw_size/PAGE_SIZE));
		printf("Read1 %3d \r\n",u16progress);	
	}
	f_close(&f1);
#endif	
	//*************************************************************		
	
	if(f_open(&f1, "fw.bin", FA_OPEN_EXISTING | FA_READ)!=FR_OK)
	{
		printf("\r\n Open fw.bin fail!!!");
		return;
	}		
	//program+verify
	u32FlashPageAddr=APPLICATIONADDRESS;
	for(i=0;i<(fw_size/PAGE_SIZE);i++)
	{
			f_read(&f1, &FlashBuf, PAGE_SIZE, &uiReadLen);
			if(uiReadLen!=PAGE_SIZE) break;
			
      for(index = 0; index < (PAGE_SIZE/4); index++)
      {
				
        FLASHStatus=FLASH_ProgramWord(( u32FlashPageAddr + (index * 4)), (*(uint32_t *)(FlashBuf + (index * 4))));

				if(FLASHStatus != FLASH_COMPLETE)
				{
					FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPRTERR);	
					break;
				}	
							
      }					
			u32FlashPageAddr+=PAGE_SIZE;	
			
		u16progress=((i*100)/(fw_size/PAGE_SIZE));
		printf("Prog %3d \r\n",u16progress);	
	}
	FLASH_Lock();
		
	f_close(&f1);
	
	//*************************************************************
#if(0)	
	if(f_open(&f1, "verify.bin", FA_CREATE_ALWAYS | FA_WRITE)!=FR_OK)
	{
		return;
	}		
	u32FlashPageAddr=APPLICATIONADDRESS;
	for(i=0;i<(fw_size/PAGE_SIZE);i++)
	{
		if(f_write(&f1, (const void *)u32FlashPageAddr, PAGE_SIZE, &uiReadLen)!=FR_OK)
		{
			printf("Write file Error\r\n");
		}			
		if(uiReadLen!=PAGE_SIZE) break;
		u32FlashPageAddr+=PAGE_SIZE;	
		
		LCD_Gotoxy(0,0);
		u16progress=((i*100)/(fw_size/PAGE_SIZE));
		printf("Read2 %3d \r\n",u16progress);
	}
	f_close(&f1);
#endif	
	//*************************************************************			
  f_mount(&g_sFatFs,"0:",NULL);		
	
}
int main(void)
{
	//char tmpChar;
	unsigned short preTmr;
	RCC_ClocksTypeDef RCC_Clocks;

	//NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x3000);
	//NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x2000);
	

	MAL_Init(0);//Set SPI SD card.

	RCC_GetClocksFreq(&RCC_Clocks);
	
	SetupUart1();
	RTC_Configuration();

	if(USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == SET)
	{
		USART_ReceiveData(USART1);//dummy read
	}
	
	printf("\r\n ****************************************");
	printf("\r\n SD Card Bootloer");
	printf("\r\n Press any key within 3sec to loader!");
	printf("\r\n ");
	printf("\r\n ****************************************");
	printf("\r\n ");
	while(1)
	{
//####		
		preTmr=RTC_GetCounter();
		printf("\r\n Now time:=%d",preTmr);
		while(1)
		{
				if(USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == SET)
				{
					//
					USART_ReceiveData(USART1);//dummy read
					
					printf("\r\n Enter Bootloer to Programming...");
					
					GotoIAP();
						
					
				}
				else
				{
					//Time out?
					if(RTC_GetCounter()>(preTmr+5))
					{
						break;//Exit loader memnu.
					}
					else
					{
						printf(".");
						delay_loop();
						delay_loop();
						delay_loop();
					}
					
				}
		}
//####
		printf("\r\n Exit Bootloer");
		//Goto user code.

		//{ /* Test if user code is programmed starting from address 0x8003000 */
		if (((*(__IO uint32_t*)ApplicationAddress) & 0x2FFE0000 ) == 0x20000000)
		{ /* Jump to user application */
			
			printf("\r\n Run User Code!!!");
			
			NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x3000);
			
			JumpAddress = *(__IO uint32_t*) (ApplicationAddress + 4);
			Jump_To_Application = (pFunction) JumpAddress;
			/* Initialize user application's Stack Pointer */
			__set_MSP(*(__IO uint32_t*) ApplicationAddress);
			Jump_To_Application();
		}	
		else
		{
			//BAD USer Code!!!
			printf("\r\n BAD USer Code Goto Reset!!!");
			delay_loop();
			delay_loop();
			delay_loop();
			NVIC_SystemReset();
		}
		
		while(1)
		{
			//Error
		}
		
				
	}//while(1)
}

#ifdef USE_FULL_ASSERT
/*******************************************************************************
* Function Name  : assert_failed
* Description    : Reports the name of the source file and the source line number
*                  where the assert_param error has occurred.
* Input          : - file: pointer to the source file name
*                  - line: assert_param error line source number
* Output         : None
* Return         : None
*******************************************************************************/
void assert_failed(uint8_t* file, uint32_t line)
{
  /* User can add his own implementation to report the file name and line number,
     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */

  /* Infinite loop */
  while (1)
  {}
}
#endif

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
